﻿using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace TaskProject
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 模拟从数据库中获取数据，并将数据更新到UI控件中的过程
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn1_Click(object sender, RoutedEventArgs e)
        {
            //UI界面动态更新是UI线程控制的，但是点击控件之后，执行从数据库汇获取数据方法
            //如果有10万条数据，那么就会卡顿在这一步，UI线程无法继续下去，俗称卡UI线程了。
            Thread.Sleep(3000);
            MessageBox.Show("白菜做好了，请享用！！！");
            Thread.Sleep(5000);
            MessageBox.Show("红烧肉做好了，请享用！！！");
        }

        /// <summary>
        /// 模拟使用Thread线程方法，利用多线程的方式去解决UI界面卡顿的事情。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn2_Click(object sender, RoutedEventArgs e)
        {
            //方式1：Thread+Lambda表达式
            Thread thread = new Thread(() =>
            {
                Thread.Sleep(3000);
                MessageBox.Show("白菜做好了，请享用！！！");
                Thread.Sleep(5000);
                MessageBox.Show("红烧肉做好了，请享用！！！");
            });
            thread.Start();

            //方式2：
            Thread threadTest = new Thread(AAA.Read);
            threadTest.Start();


            //弊端
            //1.资源消耗过高
            //创建和销毁线程需要消耗大量的系统资源。如果频繁地创建和销毁线程，可能会导致性能下降甚至内存溢出。

            //2.线程间的通信复杂
            //当多个线程需要共享数据或进行通信时，必须小心处理同步问题，否则可能导致死锁、竞态条件等错误。

            //3. 难以调试和维护
            //多线程程序的逻辑通常比单线程程序更加复杂，尤其是在涉及线程安全和并发控制时。这使得程序更难调试和维护。

            //4. 死锁风险
            //当多个线程互相等待对方释放资源时，可能会导致死锁，从而使程序无法继续运行。

            //5. 上下文切换开销
            //线程之间的频繁切换会增加 CPU 的负担，从而降低程序的整体性能。

            //个人总结：
            //1.在使用Thread解决线程问题时，必须先创建一个对象，然后是启用，暂停，销毁线程，比较复杂，每一步都需要注意。
            //2.更为重要的是应用程序中有一个线程池，按理来说应该先使用线程池中的空闲线程，没有了再创建新的，结果使用Thread时直接创建了一个新的对象，创建和销毁都是对资源的一种浪费。
        }

        /// <summary>
        /// 模拟使用Task任务解决多线程问题
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn3_Click(object sender, RoutedEventArgs e)
        {
            Task.Run(() =>
            {
                Thread.Sleep(3000);
                MessageBox.Show("白菜做好了，请享用！！！");
                Thread.Sleep(5000);
                MessageBox.Show("红烧肉做好了，请享用！！！");
            });

            //Task 并不是直接对 Thread 的简单封装，而是基于线程池（ThreadPool）来实现的。
            //具体来说，当创建一个 Task 时，它会尝试从线程池中获取一个可用的线程来执行任务，而不是每次都创建一个新的线程。
            //这种方式减少了频繁创建和销毁线程所带来的开销，从而提升了性能。


            //总结：
            //Task 并不是简单地对 Thread 进行封装，而是通过线程池机制实现了一种更高层次的抽象。
            //它不仅优化了性能，还提供了更强大的功能支持。因此，可以说 Task 在某种程度上间接依赖于 Thread，但它的设计目标和实现方式远远超出了单纯封装的范畴。
        }

        private void btn4_Click(object sender, RoutedEventArgs e)
        {
            Task.Run(() =>
            {
                Thread.Sleep(5000);
                MessageBox.Show("红烧肉做好了，请享用！！！");
            });

            Task.Run(() =>
            {
                Thread.Sleep(3000);
                MessageBox.Show("白菜做好了，请享用！！！");

            });

            //前面的Thread方法+Task方法，都是多使用了一个线程，但是里面的内容是顺序执行的，
            //同时如果里面是有两个方法，我这里可以通过两个Task方法，来分别执行这两个方法。
        }

        private void btn5_Click(object sender, RoutedEventArgs e)
        {
            Task.Run(() =>
            {
                Thread.Sleep(3000);
                MessageBox.Show("白菜做好了，请享用！！！");
                Thread.Sleep(5000);
                MessageBox.Show("红烧肉做好了，请享用！！！");
            });
            MessageBox.Show("这里本应该是最后一句！！！");


            //在使用Task时候，有一个很严重的问题。
            //例如：Task中使用了从数据库中获取数据的方法，后面还有需要执行的语句，那么可能会造成一种错误
            //错误1：后面的语句先执行了，前面Task方法中的语句后执行了就很难搞。
            //错误2：前面是定义了一个集合，中间的Task语句中是对集合进行赋值，最后是将集合中的数据进行操作。
            //但是这个时候，就容易报错了，因为没有数据。
        }

        private  async void btn6_Click(object sender, RoutedEventArgs e)
        {
            //严谨一点的说法是：标记了async，在await之前还是同步方法，只是一碰到await这个关键字之后，才是异步方法。

            //当使用 await Task.Run 时，调用方不会被阻塞，而是会立即返回并继续执行后续代码。
            //一旦后台任务完成，控制权会自动返回到调用方，并继续执行 await 后的代码。这种方式显著提升了程序的并发性和响应性。
            await Task.Run(() =>
            {
                Thread.Sleep(3000);
                MessageBox.Show("白菜做好了，请享用！！！");
                Thread.Sleep(5000);
                MessageBox.Show("红烧肉做好了，请享用！！！");
            });
            MessageBox.Show("这里本应该是最后一句！！！");

            //同步和异步
            //同步：一根水管，顺序123执行；异步：遇见难以处理的事情，先解决后面简单的，等简单的解决完后，再来解决困难的，可能是213执行。
        }

        private async void btn7_Click(object sender, RoutedEventArgs e)
        {

            //await 本身就有等待，挂起的意思，两个同样异步执行的Task任务，那么就变成同步的了。
            await Task.Run(() =>
            {
                Thread.Sleep(5000);
                MessageBox.Show("红烧肉做好了，请享用！！！");
            });

            await Task.Run(() =>
            {
                Thread.Sleep(3000);
                MessageBox.Show("白菜做好了，请享用！！！");
            });
            MessageBox.Show("这里本应该是最后一句！！！");
        }

        private void btn8_Click(object sender, RoutedEventArgs e)
        {
            List<Task> tasks = new List<Task>();
            tasks.Add(Task.Run(() =>
            {
                Thread.Sleep(5000);
                MessageBox.Show("红烧肉做好了，请享用！！！");
            })
            );
            tasks.Add(Task.Run(() =>
            {
                Thread.Sleep(3000);
                MessageBox.Show("白菜做好了，请享用！！！");
            })
              );

            Task.WhenAll(tasks).ContinueWith(t =>
            {
                MessageBox.Show("这里本应该是最后一句！！！");
            }); 
        }
    }
}



public static class AAA
{
    public static void Read()
    {
        Thread.Sleep(3000);
        MessageBox.Show("白菜做好了，请享用！！！");
        Thread.Sleep(5000);
        MessageBox.Show("红烧肉做好了，请享用！！！");
    }
}